package com.zyl.cas;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author zhaoyl
 * @date 2024/5/20 18:16
 * @description 说明
 * CAS（Compare And Swap）是一种原子算法，用于实现无锁并发操作。它的核心思想是在比较并交换操作中，
 * 只有当内存中的值与预期值相同时，才会将内存中的值更新为新值。如果内存中的值与预期值不同，则说明有其他线程已经修改过该值，
 * 当前线程则不进行任何操作。CAS操作通过CPU的原子指令实现，保证了操作的原子性，从而避免了线程间的数据竞争和死锁问题。
 *
 * 缺点：1.循环会耗时间，2.一次性只能保证一个共享变量的原子性 3.ABA问题。
 */
public class CASDemo {
    public static void main(String[] args) {
        //实现了CAS:
        AtomicInteger atomicInteger  = new AtomicInteger(1024);//初始值
        //如果是期望值那么执行操作，如果不是一直循环。
       // atomicInteger.getAndIncrement();//+1

        //乐观锁原理：带版本号
        //注意 Integer 使用了对象缓存机制，默认范围是 -128-127 ，推荐使用静态工厂方法ValueOf获取对象实例，而不是new,
        // 因为valueOf使用缓存，而new一定会创建新的对象分配新的内存空间
        /**
         * 避坑 AtomicStampedReference<Integer>
         * Integer对-128~127间的数字有缓存，所以在此区间的current==expectedReference为true，当current>127,每次装箱将返回新的Integer对象，此时current！=expectedReference导致compareAndSet一直返回false。
         * 超过127以后的装箱数据比较将会返回false，所以AtomicStampedReference<Integer>d的AtomicStampedReference.compareAndSet方法永远无法增长到128以后。
         * */
        AtomicStampedReference<String>  atomicStamped = new AtomicStampedReference<String>("1024",1);

        //cas：compareAndSet比较并交换
        // compareAndSet(int expect, int update) ,参数：（期望,跟新）
        //如果期望值是1024，则更新值为1314
        System.out.println(atomicInteger.compareAndSet(1024,1314));//true
        System.out.println(atomicInteger.get());//1314

        System.out.println("============ABA===============");
        System.out.println(atomicInteger.compareAndSet(1314,1024));//true
        System.out.println(atomicInteger.get());//1314
        System.out.println("=============ABA==============");

        //如果期望值不是1024，则不更新（不应该跟新）
        System.out.println(atomicInteger.compareAndSet(1024,6666));//true
        System.out.println(atomicInteger.get());//6666

        System.out.println("================CAS乐观锁=================");

        new Thread(()->{
            int stamp = atomicStamped.getStamp();//获取版本号
            System.out.println("线程A版本号=>"+stamp);//线程A版本号=>1
            try {
                TimeUnit.SECONDS.sleep(2);//延迟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //附带更新版本号
            System.out.println(atomicStamped.compareAndSet("1024","1314",stamp,stamp+1));//true
            System.out.println("线程A-1-CAS版本号=>"+atomicStamped.getStamp());//线程A-1-CAS版本号=>2
            System.out.println("线程A-1->"+atomicStamped.getReference());//1314
            //在改回去:ABA问题，变更版本号
            System.out.println(atomicStamped.compareAndSet("1314","1024",stamp,stamp+1));//true
            System.out.println("线程A-2-CAS版本号=>"+atomicStamped.getStamp());//线程A-2-CAS版本号=>3
            System.out.println("线程A-2->"+atomicStamped.getReference());//线程A-2->1024
            },"线程A").start();

        new Thread(()->{
            int stamp = atomicStamped.getStamp();//获取版本号
            System.out.println("线程B版本号=>"+stamp); //线程B版本号=>1

            try {
                TimeUnit.SECONDS.sleep(4);//延迟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //这里会修改失败?版本号不一致
            System.out.println(atomicStamped.compareAndSet("1024","6666",stamp,stamp+1));//false
            System.out.println("线程B-1-CAS版本号=>"+atomicStamped.getStamp());//线程B-1-CAS版本号=>3
            System.out.println("线程B-1->"+atomicStamped.getReference());//线程B-1->1024
        },"线程B").start();

    }

}
